import {Color} from '../../three.module.js';

class Lut {

  constructor(colormap, count = 32) {

    this.lut = [];
    this.map = [];
    this.n = 0;
    this.minV = 0;
    this.maxV = 1;

    this.setColorMap(colormap, count);

  }

  set(value) {

    if (value.isLut === true) {

      this.copy(value);

    }

    return this;

  }

  setMin(min) {

    this.minV = min;

    return this;

  }

  setMax(max) {

    this.maxV = max;

    return this;

  }

  setColorMap(colormap, count = 32) {

    this.map = ColorMapKeywords[colormap] || ColorMapKeywords.rainbow;
    this.n = count;

    const step = 1.0 / this.n;

    this.lut.length = 0;

    for (let i = 0; i <= 1; i += step) {

      for (let j = 0; j < this.map.length - 1; j++) {

        if (i >= this.map[j][0] && i < this.map[j + 1][0]) {

          const min = this.map[j][0];
          const max = this.map[j + 1][0];

          const minColor = new Color(this.map[j][1]);
          const maxColor = new Color(this.map[j + 1][1]);

          const color = minColor.lerp(maxColor, (i - min) / (max - min));

          this.lut.push(color);

        }

      }

    }

    return this;

  }

  copy(lut) {

    this.lut = lut.lut;
    this.map = lut.map;
    this.n = lut.n;
    this.minV = lut.minV;
    this.maxV = lut.maxV;

    return this;

  }

  getColor(alpha) {

    if (alpha <= this.minV) {

      alpha = this.minV;

    } else if (alpha >= this.maxV) {

      alpha = this.maxV;

    }

    alpha = (alpha - this.minV) / (this.maxV - this.minV);

    let colorPosition = Math.round(alpha * this.n);
    colorPosition == this.n ? colorPosition -= 1 : colorPosition;

    return this.lut[colorPosition];

  }

  addColorMap(name, arrayOfColors) {

    ColorMapKeywords[name] = arrayOfColors;

    return this;

  }

  createCanvas() {

    const canvas = document.createElement('canvas');
    canvas.width = 1;
    canvas.height = this.n;

    this.updateCanvas(canvas);

    return canvas;

  }

  updateCanvas(canvas) {

    const ctx = canvas.getContext('2d', {alpha: false});

    const imageData = ctx.getImageData(0, 0, 1, this.n);

    const data = imageData.data;

    let k = 0;

    const step = 1.0 / this.n;

    for (let i = 1; i >= 0; i -= step) {

      for (let j = this.map.length - 1; j >= 0; j--) {

        if (i < this.map[j][0] && i >= this.map[j - 1][0]) {

          const min = this.map[j - 1][0];
          const max = this.map[j][0];

          const minColor = new Color(this.map[j - 1][1]);
          const maxColor = new Color(this.map[j][1]);

          const color = minColor.lerp(maxColor, (i - min) / (max - min));

          data[k * 4] = Math.round(color.r * 255);
          data[k * 4 + 1] = Math.round(color.g * 255);
          data[k * 4 + 2] = Math.round(color.b * 255);
          data[k * 4 + 3] = 255;

          k += 1;

        }

      }

    }

    ctx.putImageData(imageData, 0, 0);

    return canvas;

  }

}

Lut.prototype.isLut = true;

const ColorMapKeywords = {

  'rainbow': [[0.0, 0x0000FF], [0.2, 0x00FFFF], [0.5, 0x00FF00], [0.8, 0xFFFF00], [1.0, 0xFF0000]],
  'cooltowarm': [[0.0, 0x3C4EC2], [0.2, 0x9BBCFF], [0.5, 0xDCDCDC], [0.8, 0xF6A385], [1.0, 0xB40426]],
  'blackbody': [[0.0, 0x000000], [0.2, 0x780000], [0.5, 0xE63200], [0.8, 0xFFFF00], [1.0, 0xFFFFFF]],
  'grayscale': [[0.0, 0x000000], [0.2, 0x404040], [0.5, 0x7F7F80], [0.8, 0xBFBFBF], [1.0, 0xFFFFFF]]

};

export {Lut, ColorMapKeywords};
